# -*- coding: utf-8 -*-

from enum import Enum
from typing import Dict
from typing import List

from conf.entity.module.lark_config import LarkConfig


class BasePathConfig(object):
    project_path: str
    root_path: str


class IceConfig(BasePathConfig):
    """
    ice config
    """
    file_name: str
    servant_path: str
    servant_suffix: str

    def __init__(self, project_path: str, root_path: str, file_name: str, servant_path: str, servant_suffix: str):
        self.project_path = project_path
        self.root_path = root_path
        self.file_name = file_name
        self.servant_path = servant_path
        self.servant_suffix = servant_suffix


class GrpcServant:
    root_path: str
    root_package: str
    servant_path: str
    servant_suffix: str
    exception_handler_path: str
    exception_handler_name: str

    def __init__(self):
        self.exception_handler_path = 'handler'
        self.exception_handler_name = 'ExceptionHandler'


class ProtoConfig(BasePathConfig):
    """
    proto config
    """
    file_name: str
    package: str
    java_package: str
    service_suffix: str
    request_suffix: str
    response_suffix: str
    message_prefix: str
    enable_multiple_files: bool
    module_leading_methods: List[str]
    servant: GrpcServant

    def __init__(self):
        # methods must leading with module name
        self.module_leading_methods = [
            'save',
            'batchSave',
            'update',
            'delete',
            'put',
            'post',
            'list',
            'getByCode', 'getByCodes',
            'get', 'getAll', 'getByName',
            'search'
        ]

    def add_module_leading_method(self, method: str):
        self.module_leading_methods.append(method)

    def add_module_leading_methods(self, methods: List[str]):
        if methods is not None and len(methods) > 0:
            for method in methods:
                self.add_module_leading_method(method)


class JavaConfig(BasePathConfig):
    """
    Java config
    """
    # int order to parse all domains under it
    domain_path: str
    domains: List[str]


class GrpcAndDomainConverterConfig(BasePathConfig):
    root_package: str
    converter_path: str
    domain_path: str
    default_suffix: str


class GrpcLarkConfig(LarkConfig):
    """
    lark config
    """
    pass


class GrpcMappingTypeEnum(Enum):
    STRUCT = 1
    SERVICE = 2
    METHOD = 3
    CONVERTER = 4
    SERVANT = 5


class GrpcMapping(object):
    mapping_type: GrpcMappingTypeEnum
    grpc: str
    ice: str
    java: str
    module: str

    def __init__(self, ice: str, grpc: str, module: str, mapping_type: GrpcMappingTypeEnum):
        self.grpc = grpc
        self.ice = ice
        self.module = module
        self.mapping_type = mapping_type

    def __getitem__(self, item):
        pass


class GrpcMappingConfig(object):
    ice_2_grpc: Dict[str, GrpcMapping]
    grpc_2_ice: Dict[str, GrpcMapping]
    java_2_grpc: Dict[str, GrpcMapping]
    grpc_2_java: Dict[str, GrpcMapping]

    def __init__(self):
        self.ice_2_grpc = {}
        self.grpc_2_ice = {}
        self.java_2_grpc = {}
        self.grpc_2_java = {}

    def add_mapping(self, mapping: GrpcMapping):
        def check_mapping_field(field_name: str):
            return mapping[field_name] is not None and mapping[field_name] != ''

        if check_mapping_field('ice'):
            self.ice_2_grpc[mapping.ice] = mapping
        if check_mapping_field('java'):
            self.java_2_grpc[mapping.java] = mapping
        self.grpc_2_ice[mapping.grpc] = mapping
        self.grpc_2_java[mapping.grpc] = mapping


class GrpcConfig(object):
    ice_config: IceConfig
    proto_config: ProtoConfig
    java_config: JavaConfig
    converter_config: GrpcAndDomainConverterConfig
    lark_config: GrpcLarkConfig
    mapping_config: GrpcMappingConfig
    test_mode: bool
    gen_proto_from_ice: bool
    gen_proto_from_java: bool
    convert_java_grpc: bool
    transfer_servant: bool
    document_lark: bool

    def __init__(self, proto: ProtoConfig,
                 gen_proto_from_ice: bool, gen_proto_from_java: bool,
                 convert_java_grpc: bool, transfer_servant: bool,
                 document_lark: bool):
        self.proto_config = proto
        self.gen_proto_from_ice = gen_proto_from_ice
        self.gen_proto_from_java = gen_proto_from_java
        self.convert_java_grpc = convert_java_grpc
        self.transfer_servant = transfer_servant
        self.document_lark = document_lark
        self.ice_config = None
        self.java_config = None
        self.converter_config = None
        self.lark_config = None

        # default test_mode is false
        self.test_mode = False

    def set_test_mode(self, test_mode: bool):
        self.test_mode = test_mode

    def set_ice_config(self, ice: IceConfig):
        self.ice_config = ice

    def set_java_config(self, java_config: JavaConfig):
        self.java_config = java_config

    def set_converter_config(self, converter_config: GrpcAndDomainConverterConfig):
        self.converter_config = converter_config

    def set_lark_config(self, lark_config: GrpcLarkConfig):
        self.lark_config = lark_config

    def set_mapping_config(self, mapping_config: GrpcMappingConfig):
        self.mapping_config = mapping_config
